package com.manage.system.web.controller;

import cn.hutool.core.thread.ThreadUtil;
import lombok.AllArgsConstructor;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.concurrent.ExecutorService;

/**
 * @author zhangqing
 * @description 这里写描述
 * @date 2021/5/18 6:35 下午
 */
@Component
@AllArgsConstructor
public class DistributedLock {

    private final StringRedisTemplate redisTemplate;

    /**
     * 使用lua脚本加锁
     * @param key
     * @param uid
     * @param expire
     * @return
     */
    public Long lock(String key,String uid,String expire){
        Long result = 0L;
        try {
            //调用lua脚本并执行
            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
            //返回类型是Long
            redisScript.setResultType(Long.class);
            //lua文件存放在resources目录下的redis文件夹内
            redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_lock.lua")));
            result = redisTemplate.execute(redisScript, Collections.singletonList(key), uid, expire);
            System.out.println("lock==" + result);
            // 加锁成功开启后台线程自动续期
            if(result==1){
                // 加锁成功, 启动一个延时线程, 防止业务逻辑未执行完毕就因锁超时而使锁释放
                PostponeTask postponeTask = new PostponeTask(key, uid, Long.parseLong(expire), this);
                ExecutorService executorService = ThreadUtil.newExecutor();
                executorService.execute(postponeTask);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public Long unlock(String key,String uid) {
        Long result = null;
        try {
            //调用lua脚本并执行
            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
            //返回类型是Long
            redisScript.setResultType(Long.class);
            //lua文件存放在resources目录下的redis文件夹内
            redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_unlock.lua")));
            result = redisTemplate.execute(redisScript, Collections.singletonList(key), uid);
            System.out.println("unlock==" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 续期锁
     * @param key 键
     * @param uid 值
     * @param expireTime 续期时间
     * @return 0：失败 1：成功
     */
    public Long renewalLock(String key,String uid,String expireTime) {
        Long result = null;
        try {
            //调用lua脚本并执行
            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
            //返回类型是Long
            redisScript.setResultType(Long.class);
            //lua文件存放在resources目录下的redis文件夹内
            redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("redis/redis_renewal.lua")));
            result = redisTemplate.execute(redisScript, Collections.singletonList(key), uid,expireTime);
            System.out.println("renewalLock==" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}
